Java线程池队列SynchronousQueue的详细原理分析

您所在的位置:网站首页 spring 线程池原理 Java线程池队列SynchronousQueue的详细原理分析

Java线程池队列SynchronousQueue的详细原理分析

2024-07-03 17:03| 来源: 网络整理| 查看: 265

Java线程池队列SynchronousQueue的详细原理分析-刘宇 一、什么是SynchronousQueue?二、SynchronousQueue类的结构图三、SynchronousQueue的小Demo四、SynchronousQueue源码分析1、构造方法2、put方法3、take方法4、栈结构4.1、常量讲解4.2、TransferStack讲解4.2.1、前期代码4.2.2、核心代码4.2.3、线程阻塞的实现4.2.4、不公平策略下队列图解 4.3、栈结构小总结 5、队列结构5.1、前期代码5.2、核心代码5.3、线程阻塞的实现5.4、公平策略下队列图解5.5、出队代码5.5、队列结构总结

CSDN博客地址:https://blog.csdn.net/liuyu973971883 文章来源:转载,原文地址:https://blog.csdn.net/weixin_41622183/article/details/89283085,感谢这位老哥的辛勤付出,写的非常棒,各位看完别忘了给这位老哥点个赞啊。如有侵权,请联系删除。

一、什么是SynchronousQueue? SynchronousQueue作为阻塞队列的时候,对于每一个take的线程会阻塞直到有一个put的线程放入元素为止,反之亦然。在SynchronousQueue内部没有任何存放元素的能力,可以理解为容量为 0。所以类似peek操作或者迭代器操作也是无效的,元素只能通过put类操作或者take类操作才有效。SynchronousQueue支持支持生产者和消费者等待的公平性策略。默认情况下:非公平。如果是公平锁的话可以保证当前第一个队首的线程是等待时间最长的线程,这时可以视SynchronousQueue为一个FIFO队列。SynchronousQueue 提供两种实现方式,分别是栈和队列的方式实现。这两种实现方式中,栈是属于非公平的策略,队列是属于公平策略。 二、SynchronousQueue类的结构图

在这里插入图片描述

三、SynchronousQueue的小Demo public class TestSynchronousQueue { public static void main(String[] args) throws Exception { //使用非公平策略 // SynchronousQueue synchronousQueue= new SynchronousQueue(); //使用公平策略 SynchronousQueue synchronousQueue= new SynchronousQueue(true); new Thread(()-> { try { synchronousQueue.put("A"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); //休眠一下,让异步线程完成 Thread.sleep(1000); new Thread(()-> { try { synchronousQueue.put("B"); } catch (InterruptedException e1) { e1.printStackTrace(); } }).start(); //休眠一下,让异步线程完成 Thread.sleep(1000); new Thread(()-> { try { Object take = synchronousQueue.take(); System.out.println(take); } catch (InterruptedException e1) { e1.printStackTrace(); } }).start(); //休眠一下,让异步线程完成 Thread.sleep(1000); //不管如何输出,都是 0 System.out.println(synchronousQueue.size()); } }

公平策略结果: 在这里插入图片描述

非公平策略结果: 在这里插入图片描述 为什么会出现这种情况?我们这里先不解释,先继续学习。

四、SynchronousQueue源码分析 1、构造方法 //默认构造,false 为非公平策略 public SynchronousQueue() { this(false); } //可选策略。可以看出使用的是不同形式的实现。 public SynchronousQueue(boolean fair) { transferer = fair ? new TransferQueue() : new TransferStack(); } 2、put方法

入队方法,该方法为阻塞方法

public void put(E e) throws InterruptedException { //入队时判断是否传入元素为空 if (e == null) throw new NullPointerException(); //入队 if (transferer.transfer(e, false, 0) == null) { Thread.interrupted(); throw new InterruptedException(); } } 3、take方法

出队方法,该方法为阻塞方法

public E take() throws InterruptedException { //出队穿个 null 就说明这个是出队 E e = transferer.transfer(null, false, 0); if (e != null) return e; Thread.interrupted(); throw new InterruptedException(); } 4、栈结构 4.1、常量讲解 REQUEST:表示这是个请求节点,从队列中取数据的标识(方法有 take,poll)DATA:表示这个是数据节点,插入数据到队列中的标识(方法有 offer,put)FULFILLING:这个表示配对成功,只有一消费者和生产者进行配对成功后,才会更改为该状态 /** 表示这是个请求节点 */ static final int REQUEST = 0; /** 数据节点 */ static final int DATA = 1; /** 匹配成功后设置的节点 */ static final int FULFILLING = 2; 4.2、TransferStack讲解 4.2.1、前期代码 static final class TransferStack extends Transferer { /** 表示这是个请求节点 */ static final int REQUEST = 0; /** 数据节点 */ static final int DATA = 1; /** 匹配成功后设置的节点 */ static final int FULFILLING = 2; /** 内部维护的 SNode 类 */ static final class SNode { volatile SNode next; // next node in stack volatile SNode match; // the node matched to this volatile Thread waiter; // to control park/unpark Object item; // data; or null for REQUESTs int mode; //0表示请求节点,1表示数据节点 SNode(Object item) { this.item = item; } //栈顶部指针 volatile SNode head; 4.2.2、核心代码

由于入队出队没太大区别。代码都是调用同一个方法,唯一的不同是传入的值是否为空。下面看看该 transfer 方法:

E transfer(E e, boolean timed, long nanos) { //空节点 SNode s = null; // constructed/reused as needed //判断是请求节点还是数据节点 int mode = (e == null) ? REQUEST : DATA; for (;;) { //拿到头指针 SNode h = head; //头指针为空,h.mode 默认是0,判断是否一致 if (h == null || h.mode == mode) { // empty or same-mode //判断是否为有设置超时时间 if (timed && nanos


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3